//===============================
//  功能 ：备注 
//  作者 ：上中野辅亚瑟王 
//  创建时间 ：2023-05-31  16-02-17 
//  Unity版本  ：2019.4.35f1 
//  变更时间 :  2023-05-31  16-02-17 
//===============================





using System;
using System.Collections.Generic;
using UnityEngine;

namespace ZS.U3D.BASE.Runtime.Event
{
    public static class EventManager
    {
        private class PostWrapper {
            public int PostFrame;
            public int EventID;
            public IEvent Message;

            public void OnRelease() {
                PostFrame = 0;
                EventID = 0;
                Message = null;
            }
        }

        private static bool _isInitialize = false;
        private static GameObject _drive = null;
        private static readonly Dictionary<int, LinkedList<Action<IEvent>>> _listeners = new Dictionary<int, LinkedList<Action<IEvent>>>();
        private static readonly List<PostWrapper> _postWrappers = new List<PostWrapper>();

        public static void Initalize() {
            if (_isInitialize)
            {
                MyDebug.LogWarning($"{nameof(EventManager)} 已经初始化，无需再次初始化 ，请删除多余的初始化 !");
                return;
            }

            {
                _isInitialize = true;
                _drive = new GameObject($"[{nameof(EventManager)}]");
                _drive.AddComponent<EventDriver>();
                UnityEngine.Object.DontDestroyOnLoad(_drive);
                MyDebug.Log($"{nameof(EventManager)} 初始化完毕 ");
            }

        }

        public static void AddListener<TEvent>(Action<IEvent> listener)where TEvent:IEvent 
        {
            Type eventType = typeof(TEvent);
            AddListener(eventType,listener);
        }

        /// <summary>
        /// 添加监听
        /// </summary>
        internal static void AddListener(Type eventType, Action<IEvent> listener)
        {
            int eventId = eventType.GetHashCode();
            AddListener(eventId, listener);
        }

        /// <summary>
        /// 添加监听
        /// </summary>
        internal static void AddListener(int eventId, Action<IEvent> listener)
        {
            if (_listeners.ContainsKey(eventId) == false) 
            {
                _listeners.Add(eventId, new LinkedList<Action<IEvent>>());
            }

            if (_listeners[eventId].Contains(listener) == false)
            {
                _listeners[eventId].AddLast(listener);
            }  
        }

        /// <summary>
		/// 移除监听
		/// </summary>
		public static void RemoveListener<TEvent>(Action<IEvent> listener) where TEvent : IEvent
        {
            Type eventType = typeof(TEvent);
            RemoveListener(eventType, listener);
        }

        /// <summary>
        /// 移除监听
        /// </summary>
        public static void RemoveListener(Type eventType, Action<IEvent> listener)
        {
            int eventId = eventType.GetHashCode();
            RemoveListener(eventId, listener);
        }

        /// <summary>
        /// 移除监听
        /// </summary>
        public static void RemoveListener(int eventId, Action<IEvent> listener)
        {
            if (_listeners.ContainsKey(eventId))
            {
                if (_listeners[eventId].Contains(listener)) 
                {
                    _listeners[eventId].Remove(listener);
                }
            }
        }

        /// <summary>
        /// 分发事件
        /// </summary>
        /// <param name="@event"></param>
        public static void FireEvent(IEvent @event) {
            int eventId = @event.GetType().GetHashCode();
            FireEvent(eventId,@event);
        }

        /// <summary>
        /// 分发事件
        /// </summary>
        /// <param name="eventId"></param>
        /// <param name="event"></param>
        internal static void FireEvent(int eventId,IEvent @event) {
            if (_listeners.ContainsKey(eventId) == false)
                return;
            LinkedList<Action<IEvent>> listeners = _listeners[eventId];
            if (listeners.Count>0)
            {
                var currentNode = listeners.Last;
                while (currentNode!=null)
                {
                    currentNode.Value.Invoke(@event);
                    currentNode = currentNode.Previous;
                }
            }
        }

        /// <summary>
        /// 延迟广播事件
        /// </summary>
        public static void PostMessage(IEvent message)
        {
            int eventId = message.GetType().GetHashCode();
            PostMessage(eventId, message);
        }

        /// <summary>
        /// 延迟广播事件
        /// </summary>
        public static void PostMessage(int eventId, IEvent message)
        {
            var wrapper = new PostWrapper();
            wrapper.PostFrame = Time.frameCount;
            wrapper.EventID = eventId;
            wrapper.Message = message;
            _postWrappers.Add(wrapper);
        }

        internal static void Update() {
            if (_postWrappers.Count>0)
            {
                for (int i = _postWrappers.Count - 1; i >= 0; i--)
                {
                    var wrapper = _postWrappers[i];
                    if (Time.frameCount > wrapper.PostFrame)
                    {
                        FireEvent(wrapper.EventID, wrapper.Message);
                        _postWrappers.RemoveAt(i);
                    }
                }
            }
        }


        /// <summary>
        /// 清空所有监听
        /// </summary>
        public static void ClearAll()
        {
            foreach (int eventId in _listeners.Keys)
            {
                _listeners[eventId].Clear();
            }
            _listeners.Clear();
            _postWrappers.Clear();
        }


        public static void Destroy() 
        {
            if (_isInitialize)
            {
                ClearAll();

                _isInitialize = false;
                if (_drive!=null)
                {
                    UnityEngine.Object.Destroy(_drive);
                }
                MyDebug.Log($"{nameof(EventManager)} 已经被销毁");
            }
        }

    }
}
